/*
Polhemus Tracker Terminal version 1.0.0 -- Terminal Interface to Polhemus Trackers: Fastrak, Patriot, and Liberty
Copyright  ©  2009  Polhemus, Inc.

Converted t command-line version by Mike Ciaraldi 2001/07/26

This file is part of Tracker Terminal.

Tracker Terminal is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Tracker Terminal is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Tracker Terminal.  If not, see <http://www.gnu.org/licenses/>.

*************************************************************************

Tracker Terminal version 1.0.0 uses the libusb library version 1.0
libusb Copyright © 2007-2008 Daniel Drake <dsd@gentoo.org>
libusb Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com>
Licensed under the GNU Lesser General Public License version 2.1 or later.
*/

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include "PiTracker.h"
#include "PingPong.h"
#include "PiPeek.h"
#include "PiParams.h"

#define CNX_FILE   PACKAGE_LOCAL_STATE_DIR_PITERM"/PiPeek_params.cnx"
#define LOGO_FILE  PACKAGE_DATA_ROOT_DIR_PITERM"/PiTermIcon.png"

#define BUFFER_SIZE   1000


int main(int argc,char* argv[]){

  CAP_STRUCT cs;
  CNX_STRUCT cnxStruct;

  PingPong pong;
  if (pong.InitPingPong(BUFFER_SIZE)<0){
    fprintf(stderr,"Memory Allocation Error setting up buffers\n");
    return -1;
  }

  int keepLooping=0;


  cs.fCap=NULL;
  cs.filename=NULL;

  int useDefault=true;
  CNX_PARAMS cp;


  // check for an existing parameter file, if it exists use that data,
  // otherwise load defaults

#if 0 
 if (g_file_test(CNX_FILE,G_FILE_TEST_EXISTS)){
      FILE* f=fopen(CNX_FILE,"r+");
      int br=fread(&cp,sizeof(CNX_PARAMS),1,f);
      if (br==1){
	  useDefault=FALSE;
	  cnxStruct.cnxType=cp.cnxType;
	  cnxStruct.trackerType=cp.tracker;
      }
      fclose(f);
  }
#endif

  if (useDefault){
    cnxStruct.cnxType=USB_CNX;

    //cnxStruct.trackerType=TRKR_LIB_HS;
    cnxStruct.trackerType=TRKR_LIB;
    strncpy(cp.port,"/dev/ttyS0",50);
  }

  // The communication with the tracker
  cnxStruct.pTrak=new PiTracker;
  if (!cnxStruct.pTrak){
    printf("Memory Allocation Error creating tracker communications module\n");
    return -3;
  }

  echo(&cnxStruct); // Read the tracker and echo to the stdout.

#if 0 
  // set up read_write structs to read data in worker thread,
  // use timeout func to write the data to the textview
  
  // create structs to be used in Read thread and the write timeout fxn
  pthread_t thread_id;
  READ_WRITE_STRUCT readStruct={&pong,keepLooping,&thread_id,cnxStruct.pTrak};
  READ_WRITE_STRUCT writeStruct={&pong,keepLooping,&thread_id,NULL};  // will add textview after it's created

  // closing down, time to clean up
  // close capture file if open
  if (cs.fCap)
    fclose(cs.fCap);

  // clean up thread if still connected
  if (keepLooping){
    keepLooping=0;
    pthread_join(thread_id,NULL);  // wait on the thread to finish
    cnxStruct.pTrak->CloseTrk();
  }

#endif

#if 0
  // save connection parameters for next time
  FILE* f=fopen(CNX_FILE,"w");
  if (f){
    cp.cnxType=cnxStruct.cnxType;
    cp.tracker=cnxStruct.trackerType;
    fwrite(&cp,sizeof(CNX_PARAMS),1,f);
    fclose(f);
  }
#endif

  delete cnxStruct.pTrak;
  return 0;

}

void echo(LPCNX_STRUCT pcs) {
  int cnxSuccess;
  char* str;
  char* port;

  printf("About to open USB port.\n");

  if (pcs->cnxType==USB_CNX){
      cnxSuccess=pcs->pTrak->UsbConnect(usbTrkParams[pcs->trackerType].vid,
					usbTrkParams[pcs->trackerType].pid,
					usbTrkParams[pcs->trackerType].
					writeEp,usbTrkParams[pcs->trackerType].readEp);
   
      if (cnxSuccess!=0){  // failure
	fprintf(stderr, "Unable to open USB.\n");
	return;
      }
    
    printf("Connected to %s over USB.\n",trackerNames[pcs->trackerType]);
   }

  else {    // rs232
#if 0
   /port=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pcs->portChooser));
    cnxSuccess=pcs->pTrak->Rs232Connect(port);
    if (cnxSuccess!=0){
      msg=gtk_message_dialog_new(NULL,GTK_DIALOG_MODAL,GTK_MESSAGE_WARNING,GTK_BUTTONS_OK,
				 "Unable to connect to RS232 port %s.",port);
      gtk_dialog_run(GTK_DIALOG(msg));
      gtk_widget_destroy(msg);
      g_free(port);
      return;
    }
#endif

  }

  BYTE buf[BUFFER_SIZE];
  LPREAD_WRITE_STRUCT prs=(LPREAD_WRITE_STRUCT)pcs;
  PiTracker* pTrak=(PiTracker*)pcs->pTrak;
  //PiTracker* pTrak=(PiTracker*)prs->pParam;
  int len=0;
  int bw;

#if 0
  // first establish comm and clear out any residual trash data
  do {
    pTrak->WriteTrkData((void*)"\r",1);  // send just a cr, should return an short "Invalid Command" response
    usleep(100000); // sleep 100 msec.

    len=pTrak->ReadTrkData(buf,BUFFER_SIZE);  // keep trying till we get a response
  } while (!len);
#endif

  //pTrak->WriteTrkData((void*)"C\r",2); // Request continuous output

  while (prs->keepLooping){
    pTrak->WriteTrkData((void*)"P",1); // Request one output
    len=pTrak->ReadTrkData(buf,BUFFER_SIZE);  // read tracker data
    if (len>0 && len<BUFFER_SIZE){
      buf[len]=0;  // null terminate
      printf("Received: %s", buf);
#if 0
      do {
	bw=prs->pPong->WritePP(buf,len);  // write to buffer
	usleep(1000);
      }while(!bw);
#endif

    }
    usleep(2000);  // rest for 2ms
  }

  return;




}

#if 0
// connect to the tracker and start the read thread and write timeout
void OnConnect(GtkWidget* w,LPCNX_STRUCT pcs){

  int cnxSuccess;
  gchar* str;
  gchar* port;
  GtkWidget* msg;


  if (pcs->cnxType==USB_CNX){
    do {
      cnxSuccess=pcs->pTrak->UsbConnect(usbTrkParams[pcs->trackerType].vid,usbTrkParams[pcs->trackerType].pid,
				      usbTrkParams[pcs->trackerType].writeEp,usbTrkParams[pcs->trackerType].readEp);
   
      if (cnxSuccess!=0){  // failure
	if (QueryUser4TrackerType(pcs->trackerType)==-1)  // user cancelled out
	  return;
      }
    
    } while (cnxSuccess!=0);

    // set label
    str=g_strconcat("Connected to ",trackerNames[pcs->trackerType]," over USB",NULL);
    gtk_label_set_text(pcs->cnxLabel,str);
    g_free(str);
  }

  else {    // rs232
    port=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pcs->portChooser));
    cnxSuccess=pcs->pTrak->Rs232Connect(port);
    if (cnxSuccess!=0){
      msg=gtk_message_dialog_new(NULL,GTK_DIALOG_MODAL,GTK_MESSAGE_WARNING,GTK_BUTTONS_OK,
				 "Unable to connect to RS232 port %s.",port);
      gtk_dialog_run(GTK_DIALOG(msg));
      gtk_widget_destroy(msg);
      g_free(port);
      return;
    }

     // set label
    str=g_strconcat("Connected over RS232 at port ",port,NULL);
    gtk_label_set_text(pcs->cnxLabel,str);
    g_free(port);
    g_free(str);
  }

  // disable connect, enable disconnect
  GtkWidget* disconnect=GTK_WIDGET(g_object_get_data(G_OBJECT(w),"disconnect"));
  gtk_widget_set_sensitive(w,FALSE);
  gtk_widget_set_sensitive(disconnect,TRUE);

  // start read thread

  LPREAD_WRITE_STRUCT prs=(LPREAD_WRITE_STRUCT)g_object_get_data(G_OBJECT(w),"readstruct");
  prs->keepLooping=1;
  pthread_create(prs->pthread,NULL,ReadTrackerThread,prs);

   // start the write thread
  gpointer p=g_object_get_data(G_OBJECT(w),"writestruct");
  g_timeout_add(10,(GSourceFunc)Write2Display,p);

   // give the cmd entry the focus
  GtkWidget* entry=GTK_WIDGET(g_object_get_data(G_OBJECT(w),"entry"));
  gtk_widget_grab_focus(entry);

}
#endif

#if 0
void OnDisconnect(GtkWidget* w,LPCNX_STRUCT pcs){

  gtk_label_set_text(pcs->cnxLabel,"No Connection");
  GtkWidget* connect=GTK_WIDGET(g_object_get_data(G_OBJECT(w),"connect"));
  gtk_widget_set_sensitive(w,FALSE);
  gtk_widget_set_sensitive(connect,TRUE);

  LPREAD_WRITE_STRUCT prs=(LPREAD_WRITE_STRUCT)g_object_get_data(G_OBJECT(w),"readstruct");
  prs->keepLooping=0;
  pthread_join(*prs->pthread,NULL);  // wait for the read thread to complete
  pcs->pTrak->CloseTrk();  // close down the tracker connection

}
#endif

#if 0
// collect the key value typed and send it to the tracker
gboolean CommandEntered(GtkEntry* w,GdkEventKey* key,LPCNX_STRUCT pcs){

  const gint KEY_RETURN=0xff0d;
  const gint KEY_COMMA=0x002c;
  const gint KEY_STAR=0x002a;
  const gint KEY_POINT=0x002e;
  const gint KEY_AT=0x0040;
  int keyval=key->keyval;
  GtkWidget *dlg;
  gchar* txt;
  gboolean rv=FALSE;

  static int clearEntry=0;

  if (pcs->pTrak->GetCnxType()==NO_CNX){
    dlg=gtk_message_dialog_new(NULL,GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,
			    "No Connection with a Polhemus Tracker detected.");
    gtk_dialog_run(GTK_DIALOG(dlg));
    gtk_widget_destroy(dlg);
    return FALSE;
  }

  if(clearEntry){
    gtk_entry_set_text(w,"");
    clearEntry=0;
  }

  // these are non-alpha num keys that are valid to the tracker
  int validKey=(keyval==KEY_STAR)||(keyval==KEY_COMMA)||(keyval==KEY_POINT)||(keyval==KEY_AT);

  if ((key->type==GDK_KEY_PRESS) &&((g_ascii_isalnum(keyval))||(keyval==KEY_RETURN)||validKey)){
    if(key->state&GDK_CONTROL_MASK){  // a ctrl key
      keyval=g_ascii_tolower(keyval);
      txt=g_strdup_printf("^%c",keyval&0xff);
      gtk_entry_set_text(w,txt);
      keyval-=0x60;
      gtk_editable_set_position(GTK_EDITABLE(w),-1); // set cursor to end
      g_free(txt);
      rv=TRUE; // ^V causes the clipboard to be pasted to the entry. return TRUE to prevent it.
    }

    pcs->pTrak->WriteTrkData(&keyval,1);  // send the command to the tracker

    // if 'p' or return clear the command entry
    if ((keyval=='p')||(keyval=='P')||(keyval==KEY_RETURN))
      clearEntry=1;

  }

  return rv;
}

#endif

#if 0

// This is the thread that reads data from the tracker and stores in the
// ping pong buffer
void* ReadTrackerThread(void* pParam){

  BYTE buf[BUFFER_SIZE];
  LPREAD_WRITE_STRUCT prs=(LPREAD_WRITE_STRUCT)pParam;
  PiTracker* pTrak=(PiTracker*)prs->pParam;
  int len=0;
  int bw;

  // first establish comm and clear out any residual trash data
  do {
    pTrak->WriteTrkData((void*)"\r",1);  // send just a cr, should return an short "Invalid Command" response
    usleep(100000);
    len=pTrak->ReadTrkData(buf,BUFFER_SIZE);  // keep trying till we get a response
  } while (!len);


  while (prs->keepLooping){

    len=pTrak->ReadTrkData(buf,BUFFER_SIZE);  // read tracker data
    if (len>0 && len<BUFFER_SIZE){
      buf[len]=0;  // null terminate
      do {
	bw=prs->pPong->WritePP(buf,len);  // write to buffer
	usleep(1000);
      }while(!bw);
    }
    usleep(2000);  // rest for 2ms
  }

  return NULL;
}
#endif

#if 0
// This is a timeout fxn that will read the ping pong buffer and output to the display
// set to fire every 10 ms
gboolean Write2Display(gpointer p){

  GtkTextBuffer* buffer;
  GtkTextIter iter;
  GtkTextMark* mark;

  LPREAD_WRITE_STRUCT lws=(LPREAD_WRITE_STRUCT)p;
  BYTE buf[BUFFER_SIZE];
  GtkTextView* textview=GTK_TEXT_VIEW(lws->pParam);
  FILE** f =(FILE**)g_object_get_data(G_OBJECT(textview),"capFile");


  int len=lws->pPong->ReadPP(buf);
  while (len){
    buf[len]=0;

    // write to display
    buffer=gtk_text_view_get_buffer(textview);
    gtk_text_buffer_get_end_iter(buffer,&iter);
    gtk_text_buffer_insert(buffer,&iter,(const char*)buf,-1);
    if (*f)
      fwrite(buf,1,len,*f);

    // now scroll it down
    mark=gtk_text_buffer_create_mark(buffer,"mark",&iter,TRUE);
    gtk_text_view_scroll_mark_onscreen(textview,mark);
    gtk_text_buffer_delete_mark(buffer,mark);  // clean up
    len=lws->pPong->ReadPP(buf);
  }

  return lws->keepLooping;
}

#endif
